/*
* coder: Dzlua
* email: 505544956@qq.com
* time : 2018-04-13 14:26
*/
#pragma once
#ifndef __MANAGER_HPP__
#define __MANAGER_HPP__

#include <functional>

UI_BEGIN_NAMESPACE

class CWindow;

class CManager
    : public WTL::CMessageFilter
    , public WTL::CIdleHandler
    , public CSingleton<CManager> {
public:
    CManager()
        : UI_CLASS_SETGET_INIT(MainWindow, nullptr) {
    }
public:
    bool Init(HINSTANCE instance) {
        auto hr = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
        if (FAILED(hr)) return false;

        hr = module_.Init(nullptr, instance);
        if (FAILED(hr)) return false;

        /*
        * this resolves ATL window thunking problem
        * when Microsoft Layer for Unicode (MSLU) is used.
        */
        ::DefWindowProc(NULL, 0, 0, 0L);

        auto bret = module_.AddMessageLoop(&msg_loop_);
        if (!bret) return false;

        msg_loop_.AddMessageFilter(this);
        msg_loop_.AddIdleHandler(this);

        return true;
    }
    void Uninit() {
        this->ClearWindow();
        msg_loop_.RemoveMessageFilter(this);
        msg_loop_.RemoveIdleHandler(this);
        module_.RemoveMessageLoop();
        module_.Term();
        ::CoUninitialize();
    }
    int Run() { return msg_loop_.Run(); }
public:
    WTL::CAppModule& GetModule() { return module_; }
    WTL::CMessageLoop& GetMsgLoop() { return msg_loop_; }
    // on window destory
    void OnWindowDestroy(std::shared_ptr<CWindow>& window) {
        this->RemoveWindow(window);
        if (!this->IsMainWindow(window)) return;

        auto arr = this->GetWindowMap();
        for (auto itor = arr.begin(); itor != arr.end(); ++itor) {
            auto wnd = std::dynamic_pointer_cast<IWindow>(itor->second);
            if (wnd) wnd->DestroyWindow();
        }
        ::PostQuitMessage(0);
    }
public:
    // for windows
    UI_CLASS_MAP_FUNS(tstring, std::shared_ptr<CWindow>, Window);
    // for idle
    UI_CLASS_SIMPLE_ARRAY_FUNS(std::function<void(void)>, Idle)
    // for main window
    UI_CLASS_SETGET_FUNS(std::shared_ptr<CWindow>, MainWindow)
public:
    bool IsMainWindow(std::shared_ptr<CWindow>& wnd) { return wnd == this->GetMainWindow(); }
protected:
    // WTL::CMessageFilter
    virtual BOOL PreTranslateMessage(MSG* pMsg) {
        auto arr = this->GetWindowMap();
        for (auto itor = arr.begin(); itor != arr.end(); ++itor) {
            auto wnd = std::dynamic_pointer_cast<IWindow>(itor->second);
            if (!wnd) continue;
            if (pMsg->hwnd != wnd->m_hWnd && !wnd->IsChild(pMsg->hwnd))
                continue;
            if (wnd->TranslateAccelerator(pMsg))
                return TRUE;
            if (wnd->PreMessageHandler(pMsg))
                return TRUE;
        }
		
		return FALSE;
    }
    // WTL::CIdleHandler
    virtual BOOL OnIdle() {
        /*
        * for idle.
        */
        auto arr = this->GetIdleArray();
        for (auto itor = arr.begin(); itor != arr.end(); ++itor) {
            (*itor)();
        }
        return FALSE;
    }
protected:
    WTL::CAppModule module_;
    WTL::CMessageLoop msg_loop_;
};

UI_END_NAMESPACE

#endif
